# -*- coding: utf-8 -*-
"""
类型转换工具函数

提供统一的类型转换代码生成接口，用于处理 any 类型（mc::variant）到强类型的转换。
使用 mcpy 提供的辅助函数（cast.h）简化代码生成。
"""

from typing import Optional


def is_weak_type(cpp_type: str) -> bool:
    """检查是否为弱类型（不需要显式转换）

    弱类型包括：
    - mc::variant（any 类型）
    - mc::variants（list[any]）
    - mc::dict（dict 类型，内部使用 variant）

    Args:
        cpp_type: C++ 类型字符串

    Returns:
        bool: 是否为弱类型
    """
    weak_types = {"mc::variant", "mc::variants", "mc::dict"}

    # 直接匹配
    if cpp_type in weak_types:
        return True

    # 检查泛型类型（如 mc::array<mc::variant>）
    for weak_type in weak_types:
        if cpp_type.startswith(f"{weak_type}<"):
            return True

    return False


def needs_variant_conversion(
    source_cpp_type: Optional[str], target_cpp_type: Optional[str]
) -> bool:
    """检查是否需要从 variant 进行类型转换

    转换规则：
    1. 源类型必须是 mc::variant
    2. 目标类型不能是 None
    3. 源类型和目标类型不能相同
    4. 特殊情况：variant -> dict 需要转换（虽然 dict 是弱类型）
    5. 目标类型是 variant 或 variants 不需要转换

    Args:
        source_cpp_type: 源 C++ 类型
        target_cpp_type: 目标 C++ 类型

    Returns:
        bool: 是否需要转换
    """
    # 基本检查
    if not source_cpp_type or not target_cpp_type:
        return False

    # 源类型必须是 variant
    if source_cpp_type != "mc::variant":
        return False

    # 相同类型不需要转换
    if source_cpp_type == target_cpp_type:
        return False

    # variant -> variant 或 variants 不需要转换
    if target_cpp_type in {"mc::variant", "mc::variants"}:
        return False

    # 其他所有情况都需要转换（包括 variant -> dict）
    return True


def generate_variant_cast(
    value_code: str, target_cpp_type: str, use_macro: bool = False
) -> str:
    """生成 variant 到强类型的转换代码

    使用 mcpy 提供的辅助函数（cast.h）生成转换代码。

    注意：类型安全检查在 Python 类型层（type_system.py）完成，
    如果代码能走到这里，说明类型检查已经通过。

    Args:
        value_code: 值表达式代码（如 "x", "items[0]", "data[key]"）
        target_cpp_type: 目标 C++ 类型（如 "int", "std::string"）
        use_macro: 是否使用宏（默认使用模板函数）

    Returns:
        str: 转换后的代码

    Examples:
        >>> generate_variant_cast("x", "int")
        'mcpy::cast<int>(x)'

        >>> generate_variant_cast("items[0]", "std::string")
        'mcpy::cast<std::string>(items[0])'

        >>> generate_variant_cast("x", "int", use_macro=True)
        'MCPY_VARIANT_CAST(int, x)'
    """
    if use_macro:
        return f"MCPY_VARIANT_CAST({target_cpp_type}, {value_code})"
    else:
        return f"mcpy::cast<{target_cpp_type}>({value_code})"


def generate_safe_variant_cast(value_code: str, target_cpp_type: str) -> str:
    """生成安全的 variant 转换代码（不抛异常）

    Args:
        value_code: 值表达式代码
        target_cpp_type: 目标 C++ 类型

    Returns:
        str: 转换后的代码（返回 std::optional<T>）

    Example:
        >>> generate_safe_variant_cast("x", "int")
        'mcpy::try_variant_cast<int>(x)'
    """
    return f"mcpy::try_variant_cast<{target_cpp_type}>({value_code})"


def generate_variant_cast_with_default(
    value_code: str, target_cpp_type: str, default_value: str
) -> str:
    """生成带默认值的 variant 转换代码

    Args:
        value_code: 值表达式代码
        target_cpp_type: 目标 C++ 类型
        default_value: 默认值代码

    Returns:
        str: 转换后的代码

    Example:
        >>> generate_variant_cast_with_default("x", "int", "0")
        'mcpy::variant_cast_or<int>(x, 0)'
    """
    return f"mcpy::variant_cast_or<{target_cpp_type}>({value_code}, {default_value})"


def generate_vector_cast(
    value_code: str, element_cpp_type: str, safe: bool = False
) -> str:
    """生成 variant 向量到强类型向量的转换代码

    Args:
        value_code: 向量表达式代码（如 "items", "get_list()"）
        element_cpp_type: 元素 C++ 类型（如 "int", "std::string"）
        safe: 是否使用安全转换（忽略失败的元素）

    Returns:
        str: 转换后的代码

    Examples:
        >>> generate_vector_cast("items", "int")
        'mcpy::array_cast<int>(items)'

        >>> generate_vector_cast("items", "int", safe=True)
        'mcpy::try_variant_vector_cast<int>(items)'
    """
    if safe:
        return f"mcpy::try_variant_vector_cast<{element_cpp_type}>({value_code})"
    else:
        return f"mcpy::array_cast<{element_cpp_type}>({value_code})"


def apply_variant_conversion(
    value_code: str,
    value_cpp_type: Optional[str],
    target_cpp_type: Optional[str],
    use_macro: bool = False,
) -> str:
    """应用 variant 类型转换（如果需要）

    这是一个便利函数，集成了类型检查和代码生成。

    注意：类型安全检查在 Python 类型层完成，这里只负责生成转换代码。

    Args:
        value_code: 值表达式代码
        value_cpp_type: 值的 C++ 类型
        target_cpp_type: 目标 C++ 类型
        use_macro: 是否使用宏

    Returns:
        str: 可能经过转换的代码

    Example:
        >>> apply_variant_conversion("x", "mc::variant", "int")
        'mcpy::cast<int>(x)'

        >>> apply_variant_conversion("x", "int", "int")
        'x'  # 不需要转换
    """
    if needs_variant_conversion(value_cpp_type, target_cpp_type):
        # needs_variant_conversion 已经确保 target_cpp_type 不为 None
        assert target_cpp_type is not None
        return generate_variant_cast(value_code, target_cpp_type, use_macro)
    return value_code


# ============================================================================
# 特殊转换辅助函数
# ============================================================================


def is_container_type(cpp_type: str) -> bool:
    """检查是否为容器类型

    Args:
        cpp_type: C++ 类型

    Returns:
        bool: 是否为容器类型
    """
    container_prefixes = [
        "mc::array<",
        "std::list<",
        "std::deque<",
        "std::set<",
        "std::unordered_set<",
        "mc::variants",
    ]
    return any(cpp_type.startswith(prefix) for prefix in container_prefixes)


def extract_element_type(container_cpp_type: str) -> Optional[str]:
    """从容器类型中提取元素类型

    Args:
        container_cpp_type: 容器 C++ 类型（如 "mc::array<int>"）

    Returns:
        元素类型，失败返回 None

    Examples:
        >>> extract_element_type("mc::array<int>")
        'int'

        >>> extract_element_type("mc::array<std::string>")
        'std::string'
    """
    if not container_cpp_type:
        return None

    # 查找 < 和 >
    start = container_cpp_type.find("<")
    end = container_cpp_type.rfind(">")

    if start == -1 or end == -1 or start >= end:
        return None

    return container_cpp_type[start + 1 : end].strip()


def needs_container_conversion(
    source_cpp_type: Optional[str], target_cpp_type: Optional[str]
) -> bool:
    """检查是否需要容器类型转换

    如 mc::variants -> mc::array<int>

    Args:
        source_cpp_type: 源容器类型
        target_cpp_type: 目标容器类型

    Returns:
        bool: 是否需要转换
    """
    if not source_cpp_type or not target_cpp_type:
        return False

    # 源必须是 mc::variants
    if source_cpp_type != "mc::variants":
        return False

    # 目标必须是强类型容器
    if not is_container_type(target_cpp_type):
        return False

    # 提取目标元素类型
    element_type = extract_element_type(target_cpp_type)
    if not element_type:
        return False

    # 元素类型必须是强类型
    return not is_weak_type(element_type)


def apply_container_conversion(
    value_code: str, source_cpp_type: Optional[str], target_cpp_type: Optional[str]
) -> str:
    """应用容器类型转换（如果需要）

    Args:
        value_code: 值表达式代码
        source_cpp_type: 源容器类型
        target_cpp_type: 目标容器类型

    Returns:
        str: 可能经过转换的代码
    """
    if needs_container_conversion(source_cpp_type, target_cpp_type):
        # needs_container_conversion 已经确保 target_cpp_type 不为 None
        assert target_cpp_type is not None
        element_type = extract_element_type(target_cpp_type)
        if element_type:
            return generate_vector_cast(value_code, element_type)

    return value_code


# ============================================================================
# 公共 API
# ============================================================================

__all__ = [
    # 类型检查
    "is_weak_type",
    "needs_variant_conversion",
    "needs_container_conversion",
    "is_container_type",
    "extract_element_type",
    # 代码生成
    "generate_variant_cast",
    "generate_safe_variant_cast",
    "generate_variant_cast_with_default",
    "generate_vector_cast",
    # 便利函数
    "apply_variant_conversion",
    "apply_container_conversion",
]
